package com.stox.client.ui.javafx.chartingy.model;

import com.stox.client.ui.javafx.chartingy.view.ChartingView;
import com.stox.client.ui.javafx.widget.RangeSlider;

public class Zoom {
	private double step = 0.05;
	private double resetValue = 1;
	private final ChartingView chartingView;

	public Zoom(final ChartingView chartingView) {
		this.chartingView = chartingView;
	}

	public void out() {
		final double delta = getDeltaX();
		final RangeSlider rangeSlider = chartingView.getRangeSlider();
		final double high = rangeSlider.getHighValue();
		final double low = rangeSlider.getLowValue();
		if ((high + delta) <= rangeSlider.getMax()) {
			rangeSlider.setHighValueChanging(true);
		}
		if ((low - delta) >= rangeSlider.getMin()) {
			rangeSlider.setLowValue(low - delta);
		}
		if (rangeSlider.isHighValueChanging()) {
			rangeSlider.setHighValue(high + delta);
			rangeSlider.setHighValueChanging(false);
		}

		if (chartingView.getPrimaryChart().getValueAxis().isZoomable()) {
			final double upperBound = chartingView.getPrimaryChart().getValueAxis().getUpperBound();
			final double lowerBound = chartingView.getPrimaryChart().getValueAxis().getLowerBound();
			final double deltaY = getDeltaY();
			final double futureMax = upperBound + deltaY;
			final double futureMin = lowerBound - deltaY;
			if ((futureMax <= chartingView.getPrimaryChart().getPrimaryPlot().getBackingDataMax()) &&
					(futureMin >= chartingView.getPrimaryChart().getPrimaryPlot().getBackingDataMin())) {
				chartingView.getPrimaryChart().getValueAxis().updateAxisBounds(futureMax, futureMin);
				chartingView.getPrimaryChart().updateAxisBounds();
			}
		}
	}


	private double getDeltaX() {
		final RangeSlider rangeSlider = chartingView.getRangeSlider();
		return ((rangeSlider.getMax() - rangeSlider.getMin()) * step) / 2;
	}

	private double getDeltaY() {
		return ((chartingView.getPrimaryChart().getPrimaryPlot().getBackingDataMax() - chartingView.getPrimaryChart().getPrimaryPlot().getBackingDataMin()) * step) / 2;
	}

	public void in() {
		final double deltaX = getDeltaX();
		final RangeSlider rangeSlider = chartingView.getRangeSlider();
		final double high = rangeSlider.getHighValue();
		final double low = rangeSlider.getLowValue();
		final double futureHigh = high - deltaX;
		final double futureLow = low + deltaX;
		if (futureHigh > futureLow) {
			rangeSlider.setHighValueChanging(true);
		}
		if (futureLow < futureHigh) {
			rangeSlider.setLowValue(futureLow);
		}
		if (rangeSlider.isHighValueChanging()) {
			rangeSlider.setHighValue(futureHigh);
			rangeSlider.setHighValueChanging(false);
		}

		if (chartingView.getPrimaryChart().getValueAxis().isZoomable()) {
			final double upperBound = chartingView.getPrimaryChart().getValueAxis().getUpperBound();
			final double lowerBound = chartingView.getPrimaryChart().getValueAxis().getLowerBound();
			final double deltaY = getDeltaY();
			final double futureMax = upperBound - deltaY;
			final double futureMin = lowerBound + deltaY;
			if (futureMax > futureMin) {
				chartingView.getPrimaryChart().getValueAxis().updateAxisBounds(futureMax, futureMin);
				chartingView.getPrimaryChart().updateAxisBounds();
			}
		}
	}

	public void reset() {
		final RangeSlider rangeSlider = chartingView.getRangeSlider();
		final double max = rangeSlider.getMax();
		final double min = rangeSlider.getMin();
		final double futureHigh = max;
		final double futureLow = futureHigh - ((max - min) * resetValue);
		rangeSlider.setHighValueChanging(true);
		rangeSlider.setLowValue(futureLow);
		rangeSlider.setHighValue(futureHigh);
		rangeSlider.setHighValueChanging(false);

		if (chartingView.getPrimaryChart().getValueAxis().isZoomable()) {
			chartingView.getPrimaryChart().getValueAxis().updateAxisBounds(chartingView.getPrimaryChart().getPrimaryPlot().getBackingDataMax(), chartingView.getPrimaryChart().getPrimaryPlot().getBackingDataMin());
			chartingView.getPrimaryChart().updateAxisBounds();
		}
	}

	public double getStep() {
		return step;
	}

	public void setStep(final double step) {
		this.step = step;
	}

	public double getResetValue() {
		return resetValue;
	}

	public void setResetValue(final double resetValue) {
		this.resetValue = resetValue;
	}

}
